/**
 * @author kangkai
 * ! 请注意，一个各个mc是独立的，所以享元模式已没有意义
 * 
 * 注意_x,_y,_z等要有初始值，否则就容易为undefined而导致了问题
 * 
 * 左手坐标系
 * Y向上，x向左，z向里
 * 
 * 矩阵是干啥的，就是把一个坐标系里的点变换到另一个坐标系里去，两个坐标系的关系可以构造出矩阵
 * 
 * //------
 * ,解决一转就乱的问题，原因是
*	//比较重要的一件事情，就是当我从隐藏到显示的时候，刚好camera在隐藏后动了，但显示后没动且我的位置没动，
*	//则我的优化机制会认为我没动，导致渲染的其实是在隐藏自己、移动摄象机之前的坐标,
*	//这里需要一个强制机制在我变出现的时候重新计算Mf，就是最终矩阵
*	//ok 问题解决,真是的
*	
*！！要保证一个model只有一个visu
*1 添加两个加载皮肤的函数
*
*2,LoadSkin()成功后需要通知Model强制刷新，否则他认为摄象机和模型都没动，则会不显示目标
*
*617改装，这个就是一个大接口,实现一些公共的方法，具体方法还是到各个类里做
*
*函数排序规则
*公共不需要继承的，（排序是Mesh3D,Sprite3D,Group3D）
*公共需要继承的
* 
* !! 注意关于ABH，本来是应该在visu里的，现在这个就把他做到visu里吧
* 
* !!严重注意，这里使用getter和setter来设置取得一些位置啥的是非常有用的.因为游戏中如果用md.hardVO.v3d_p.x 
* 	就太复杂了，而游戏中这种读取设置时非常非常频繁的。游戏就是设置这些视图啊
*/
package kgame5.k3d.core.obj3d.node3d {
import kgame5.k3d.core.math.Vector3D;
import kgame5.k3d.core.obj3d.info.transform.TransformInfo;
import kgame5.k3d.core.obj3d.node3d.impl.group3d.Group3D;
import kgame5.k3d.core.obj3d.node3d.impl.group3d.impl.World3D;
import kgame5.k3d.core.render.RenderSessionData;
import kgame5.k3d.core.render.layerrender.LayerRender;

import flash.display.*;
import flash.events.EventDispatcher;

public class Node3D extends EventDispatcher{
	//_____________Static_______________
	//这个保证每个model有一个唯一的bornID
	private static var BornID:int=9000;
	
	//_____________Property_______________
	public var name:String="";//名字，就是识别用的，直接原因是从3dmax里导入的时候知道模型名字
	
	//这个引入的原因是说把这个东西加到哪个layer中去,如坦克游戏中地图层，地面标志层，坦克层
	public var layerID:int=0;//
	
	//--图层排序相关
	//!!这个因为要被Array.sortOn排序，所以一定要做成public,否则编译的时候提示找不到
	public var bornID:int=-1;//这个是为了解决排序的时候两个ccz相同的mc有固定的位置的,同时也是唯一标志一个md的id的
	public var ccd2:Number=0;//Camera cordinate distance2,在摄象机坐标里的距离摄像机的距离，这个是用来层级排序的
	
	//---
	public var ti:TransformInfo;//关于移动，旋转，缩放
	
	//--渲染器，一个object就是一个渲染器,因为有融合图层，所以做成一个
	public var renderer:LayerRender;
	
	//---粒子系统要用的
	public var life:int;//存活时间，-1表示落地就死
	public var alphaSpeed:Number=0;
	
	//--额外的数据用的
	public var extraObj:Object;
	
	//_____________Method_________________
	public function Node3D(){
		bornID=BornID--;//因为在World.sort里是一个降序排列,所以要--, 目标是当两个mc的ccz相同时后出生的在前面
		
		name="Node3D"+bornID;
		
		ti=new TransformInfo();
		
		
	}
	
	//!!销毁自己 ,释放自己所占的内存，mesh3D和sprite3D用这个默认的， Loader要用其他的
	public function dispose():void{
		//T.p("Model3D.dispose");
		//1,从父中剔除
		var p:Group3D=this.getParent();
		if(p!=null){
			p.removeChild(this);
		}
	}
	
	//**********************固定的不需要子类特别实现的**************************
	
	public function isVisible():Boolean{
		return ti.hardVO.visible;
	}
	
	//---
	protected var parentNode:Group3D;
	public function setParent(p:Group3D):void{
		parentNode=p;
	}
	public function getParent():Group3D{
		return parentNode;
	}
	
	//---
	private var world:World3D=null;//保存对world的引用，就跟mc.stage一样
	
	//注意，parentNode当被从parent里删除的时候，是可能变成null的
	public function getWorld():World3D{
		
		//查找并设置自己的world
		if(world==null){
			var tempP:Group3D=parentNode;
			while(true){
				if((tempP is World3D)){
					break;
				}
				if(tempP==null){
					break;
				}
				tempP=tempP.getParent();
			}
			
			world=tempP as World3D;
		}
		
		return world;
	}
	
	//---注意,group的这个是返回的一个mc,这个要被子类继承
	public function getDO():DisplayObject{
		return renderer.getDO();
	}
	
	//***********************需要子类实现的**********************
	//=============都需要实现的
	//返回的是模型的位置旋转缩放是否变了
	//这个要返回值的原因是当位置旋转缩放都不变的时候,就不排序,因为排序是要消耗很大运算的cpu的，数目越多排序越慢
	//返回的是否改变了 自己的 位置，旋转，缩放,这些是需要重新排序的,改变了返回true,不改变是false
	//改变位置，旋转，缩放都回导致重新排深度的,
	//~~这个的作用就是计算出screenX,Y,Z,并在自己的图层里显示出来
	public function Update(renderSessionData:RenderSessionData,isParentDirty:Boolean):void{}
	//比较重要的一件事情，就是当我从隐藏到显示的时候，刚好camera在隐藏后动了，但显示后没动且我的位置没动，
	//则我的优化机制会认为我没动，导致渲染的其实是在隐藏自己、移动摄象机之前的坐标,
	//这里需要一个强制机制在我变出现的时候重新计算Mf，就是最终句镇,很简单，具体mc的出现是在G3d.Render之前和之后设定的，保证了效率
	
	
	//!!注意这个在Group3D里是要重新实现的
	public function setVisible(p_visible:Boolean):void{
		//T.p("setVisible::"+p_visible);
		//--!!很重要的补充,自己从隐藏变成显示，因为这时的Mf是过时的,需要强制重新计算Mf,
		if(ti.hardVO.visible==false && p_visible){
			ti.bForceRefresh=true;
		}
		//--
		ti.hardVO.visible=p_visible;
		
		//如果是不能显示，就直接不让他显示了；但是如果是能显示，则要先等计算完了再画出
		if(p_visible==false){
			this.getDO().visible=false;
		}
		
	}
//	//取得显示的东西在屏幕的坐标,这两个在Group3D里也要重写
//	public function getScreenX():Number{
//		return visu.getScreenX();
//	}
//	public function getScreenY():Number{
//		return visu.getScreenY();
//	}
	
	public function forceRefresh():void{
		ti.bForceRefresh=true;
	}

	//==================getter 和setter================
	public function get x():int{
		return ti.hardVO.v3d_p.x;
	}
	public function get y():int{
		return ti.hardVO.v3d_p.y;
	}
	public function get z():int{
		return ti.hardVO.v3d_p.z;
	}
	
	public function set x(_x:int):void{
		ti.hardVO.v3d_p.x=_x;
	}
	public function set y(_y:int):void{
		ti.hardVO.v3d_p.y=_y;
	}
	public function set z(_z:int):void{
		ti.hardVO.v3d_p.z=_z;
	}
	
	public function get vx():int{
		return ti.hardVO.v3d_v.x;
	}
	public function get vy():int{
		return ti.hardVO.v3d_v.y;
	}
	public function get vz():int{
		return ti.hardVO.v3d_v.z;
	}
	
	public function set vx(_vx:int):void{
		ti.hardVO.v3d_v.x=_vx;
	}
	public function set vy(_vy:int):void{
		ti.hardVO.v3d_v.y=_vy;
	}
	public function set vz(_vz:int):void{
		ti.hardVO.v3d_v.z=_vz;
	}
	
	
	public function get rotX():int{
		return ti.hardVO.v3d_r.x;
	}
	public function get rotY():int{
		return ti.hardVO.v3d_r.y;
	}
	public function get rotZ():int{
		return ti.hardVO.v3d_r.z;
	}
	
	public function set rotX(_rotX:int):void{
		ti.hardVO.v3d_r.x=_rotX;
	}
	public function set rotY(_rotY:int):void{
		ti.hardVO.v3d_r.y=_rotY;
	}
	public function set rotZ(_rotZ:int):void{
		ti.hardVO.v3d_r.z=_rotZ;
	}
	
	public function get scaleX():Number{
		return ti.hardVO.v3d_s.x;
	}
	public function get scaleY():Number{
		return ti.hardVO.v3d_s.y;
	}
	public function get scaleZ():Number{
		return ti.hardVO.v3d_s.z;
	}
	
	public function set scaleX(_scaleX:Number):void{
		ti.hardVO.v3d_s.x=_scaleX;
	}
	public function set scaleY(_scaleY:Number):void{
		ti.hardVO.v3d_s.y=_scaleY;
	}
	public function set scaleZ(_scaleZ:Number):void{
		ti.hardVO.v3d_s.z=_scaleZ;
	}
	
	public function set scale3(_scale:Number):void{
		ti.hardVO.v3d_s.fill(_scale,_scale,_scale);
	}
	
	public function get scale():Vector3D{
		return ti.hardVO.v3d_s;
	}
	
	public function get posi():Vector3D{
		return ti.hardVO.v3d_p;
	}
	
	public function get velo():Vector3D{
		return ti.hardVO.v3d_v;
	}
	
	public function get rot():Vector3D{
		return ti.hardVO.v3d_r;
	}
//	
	public function get A():int{
		return ti.hardVO.aabb.A;
	}
	public function get B():int{
		return ti.hardVO.aabb.B;
	}
	public function get H():int{
		return ti.hardVO.aabb.H;
	}
	public function get R():int{
		return ti.hardVO.bball.R;
	}
//	
//	
//	public function set A(_A:int):void{
//		hardVO.aabb.A=_A;
//	}
//	public function set B(_B:int):void{
//		 hardVO.aabb.B=_B;
//	}
//	public function set H(_H:int):void{
//		 hardVO.aabb.H=_H;
//	}
//	public function set R(_R:int):void{
//		 hardVO.bball.R=_R;
//	}
}//end of class
}
////////////////
///////////////////////特效相关//////////////////////////////////
//	//模拟坦克的震动,A是振幅,
//	private var tick_shake:int;
//	//这个很重要，因为在切换状态的时候很可能导致shakeScale出问题，就是逐渐变大
//	public function ClearShakeScale(){
//		hardVO.v3d_s.fill(1, 1, 1);
//	}
//	public function ShakeScale(A:Number){
//		tick_shake=1-tick_shake;
//		
//		if(tick_shake==0){
//			hardVO.v3d_s.y+=A;
//			hardVO.v3d_s.x-=A;
//		}else if(tick_shake==1){
//			hardVO.v3d_s.y-=A;
//			hardVO.v3d_s.x+=A;
//		}
//	}